package com.mm.fam.web.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.mm.fam.common.utils.UUIDStringPoolUtils;
import com.mm.fam.web.entity.Node;
import com.mm.fam.web.mapper.NodeMapper;
import com.mm.fam.web.service.NodeService;
import com.mm.fam.web.socket.WebSocketServerHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author dhl
 */
@Slf4j
@Service
public class NodeServiceImpl implements NodeService, InitializingBean {

    @Autowired
    private NodeMapper nodeMapper;

    @Autowired
    private WebSocketServerHandler webSocketServerHandler;

    private ScheduledExecutorService checkNodeStatusThread = new ScheduledThreadPoolExecutor(1,new BasicThreadFactory.Builder().namingPattern("schedule-pool-app").daemon(true).build());

    /**
     * 定时检查node节点链接状态
     *
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void afterPropertiesSet() throws Exception {
        checkNodeStatusThread.scheduleAtFixedRate(() -> {
            try {
                List<Node> nodeList = nodeMapper.selectList(null);
                if (nodeList != null) {
                    for (Node node : nodeList) {
                        if (webSocketServerHandler.containsNodeId(node.getNodeId())) {
                            if(node.getStatus().equals(Node.NODE_STATUS_DISCONNECTED)){
                                node.setStatus(Node.NODE_STATUS_CONNECTED);
                                nodeMapper.updateById(node);
                            }
                        } else if(node.getStatus().equals(Node.NODE_STATUS_CONNECTED)){
                            node.setStatus(Node.NODE_STATUS_DISCONNECTED);
                            nodeMapper.updateById(node);
                        }
                    }
                }
            } catch (Exception e) {
                log.error("定时检查节点状态异常", e);
            }
        }, 10, 10, TimeUnit.SECONDS);
    }

    @Override
    public List<Node> list(Integer pageNo, Integer pageSize, String description) {
        QueryWrapper wrapper = new QueryWrapper();
        if(description != null && !"".equals(description)) {
            wrapper.eq("description",description);
        }
        List list = nodeMapper.selectList(wrapper);
        return list;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(Node node) {
        if(node.getNodeId() == null || node.getNodeId() == -1){
            // 新建
            String uuid = UUIDStringPoolUtils.getUUIDString();
            node.setToken(uuid);
            node.setStatus(Node.NODE_STATUS_DISCONNECTED);
            node.setLoginTimes(0);

            nodeMapper.insert(node);
        }else{
            nodeMapper.updateById(node);
        }

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Integer id) {
        nodeMapper.deleteById(id);
    }

    @Override
    public Node nodeAuth(Node nodePo) {
        Node node = nodeMapper.selectById(nodePo.getNodeId());
        if(node != null){
            if(nodePo.getToken().equals(node.getToken())){
                return node;
            }
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateNodeLoginInfo(Node loggedinNodePo, String sessionId, String hostAddress, int port) {
        loggedinNodePo.setRecentlySessionId(sessionId);
        loggedinNodePo.setRecentlyIpAddress(hostAddress);
        loggedinNodePo.setRecentlyLoginTime(DateFormatUtils.format(new Date(),"yyyy-MM-dd HH:mm:ss"));
        loggedinNodePo.setLoginTimes(loggedinNodePo.getLoginTimes() + 1);
        loggedinNodePo.setRecentlyPort(port);
        loggedinNodePo.setStatus(Node.NODE_STATUS_CONNECTED);
        nodeMapper.updateById(loggedinNodePo);
    }

    @Override
    public void updateNodeLogoutInfo(int nodeId) {
        Node node = nodeMapper.selectById(nodeId);
        if(node != null){
            node.setStatus(Node.NODE_STATUS_DISCONNECTED);
            node.setRecentlyLogoutTime(DateFormatUtils.format(new Date(),"yyyy-MM-dd HH:mm:ss"));
            nodeMapper.updateById(node);
        }

    }

    @Override
    public Node getNodeById(int nodeId) {
        return nodeMapper.selectById(nodeId);
    }

    @Override
    public void updateContainer(int nodeId, String containerId, int status) {
        nodeMapper.updateContainer(nodeId,containerId,status);
    }
}
